/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http:  // www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "rt80km_adaptor.h"
#include <plugin.h>
#include <libusb/libusb.h>
#include <memory>
#include "HWISPRTPrinter.h"
#include "recptprinter_hilog.h"
#include "charset.h"


using namespace SwanLink::Finance;

#define CHECK_STATUS(cond, status) do {\
    if (!(cond)) {\
        m_iStatus = SUCCESS;\
    } else {\
        m_iStatus = status;\
        return m_iStatus;\
    }\
}while(0)

#define CHECK_STATUS_NO_RET(cond, status) do {\
    if (!(cond)) {\
        m_iStatus = SUCCESS;\
    } else {\
        m_iStatus = status;\
        return;\
    }\
}while(0)

// 全局默认参数
static PrintFormat g_ipfmt;

// 构造函数和接口函数实现
RT80KM_Adaptor::RT80KM_Adaptor()
{
    m_pTask = new PrinterTask();
    m_iStatus = NOT_INIT;
    m_isOpen = false;
}

RT80KM_Adaptor::~RT80KM_Adaptor()
{
    Close();
    m_isOpen = false;
    if (m_pTask) {
        delete m_pTask;
    }
}
// 公共接口
int RT80KM_Adaptor::Open(const Transport& tran)
{
    int ret;
    if (tran.mode == AM_SERIAL) {
        ret = OpenPort(SERIAL_PORT, (char*)tran.dev);
    } else if (tran.mode == AM_USB) {
        ret = OpenPort(USB_PORT, nullptr);
    } else {
        CHECK_STATUS(true, ERR_TRANS_NOT_SUPPORT);
    }
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    m_isOpen = true;
    // 设置汉字模式
    POS_Control_SetModeFontC();
    POS_Control_SetPrintFontC(0, 0, 0);
    // 获取默认值
    return m_iStatus;
}

int RT80KM_Adaptor::Close()
{
    if (!m_isOpen) {
        return SUCCESS;
    }
    m_pTask->StopPrint();
    ClosePort();
    m_isOpen = false;
    m_iStatus = ERR_DEVICE_NOT_OPEN;
    return SUCCESS;
}

bool RT80KM_Adaptor::IsOpen()
{
    if (!m_isOpen) 
        return false;
    int ret = POS_Status_RTQueryTypeStatus(1);
    return ret == 0;
}

int RT80KM_Adaptor::Reset()
{
    if (m_isOpen) {
        m_pTask->StopPrint();
    }
    
    int ret = POS_Control_ReSet();
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    return m_iStatus;
}

int RT80KM_Adaptor::GetStatus(int module, char *err)
{
    int ret = 0;
    ret = POS_Status_RTQueryTypeStatus(1);
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    ret = POS_Status_RTQueryTypeStatus(3);
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    ret = POS_Status_RTQueryTypeStatus(4);
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    return m_iStatus;
}

// 设备功能接口
int RT80KM_Adaptor::GetPrintFormat(PrintFormatType ftt)
{
    m_iStatus = SUCCESS;
    switch (ftt) {
    case PRINT_FORMAT_DENSITY:  //  灰度值
        return g_ipfmt.density;
    case PRINT_FORMAT_BOLD:  //  粗体设置
        return g_ipfmt.bold;
    case PRINT_FORMAT_REVERSE:  //  是否反白
        return g_ipfmt.reverse;
    case PRINT_FORMAT_INVERSION:  //  上下倒置
        return g_ipfmt.inversion;
    case PRINT_FORMAT_LINETHROUGH:  //  删除线
        return g_ipfmt.linethrough;
    case PRINT_FORMAT_SIZE:  //  字符大小
        return g_ipfmt.size;
    case PRINT_FORMAT_ALIGN:  //  对齐方式
        return g_ipfmt.align;
    case PRINT_FORMAT_ITALIC:  //  是否斜体
        return g_ipfmt.italic;
    case PRINT_FORMAT_HRILOC:  //  HRI字符位置条码
        return g_ipfmt.hriloc;
    default:
        m_iStatus = ERR_PRINTER_FORMAT_NOT_SUPPORT;
        break;
    }
    return m_iStatus;
}

void RT80KM_Adaptor::SetPrintFormat(PrintFormatType ftt, int value)
{
    int ret;
    m_iStatus = SUCCESS;
    switch (ftt) {
    case PRINT_FORMAT_DENSITY:   // 灰度值
        CHECK_STATUS_NO_RET(value < PF_DENSITY_LIGHT || value > PF_DENSITY_DARK, ERR_PRINTER_VALUE_OUT_RANGE);
        // 不支持
        g_ipfmt.density = value;
        ret = -1; // TSPL_SetPrinter(5, value*5);  // 0~1
        CHECK_STATUS_NO_RET(ret != 0, ERR_PRINTER_FORMAT_NOT_SUPPORT);
        return;
    case PRINT_FORMAT_BOLD:   // 粗体设置
        g_ipfmt.bold = value;
        return;
    case PRINT_FORMAT_REVERSE:  // 是否反白
        g_ipfmt.reverse = value;  // 打印时设置
        return;
    case PRINT_FORMAT_INVERSION:  //  上下倒置
        g_ipfmt.inversion = value;  // 打印时设置
        break;
    case PRINT_FORMAT_LINETHROUGH:  // 删除线
        CHECK_STATUS_NO_RET(value < PF_LINETHROUGH_NONE || value > PF_LINETHROUGH_BROKEN,
            ERR_PRINTER_VALUE_OUT_RANGE);
        g_ipfmt.linethrough = value;
        m_iStatus = ERR_PRINTER_FORMAT_NOT_SUPPORT;
        break;
    case PRINT_FORMAT_SIZE:  // 字符大小
        CHECK_STATUS_NO_RET(value < PF_SIZE_EXTRASMALL || value > PF_SIZE_EXTRALARGE,
            ERR_PRINTER_VALUE_OUT_RANGE);
        g_ipfmt.size = value;
        break;
    case PRINT_FORMAT_ALIGN:  // 对齐方式
        CHECK_STATUS_NO_RET(value < PF_ALIGN_LEFT || value > PF_ALIGN_RIGHT,
            ERR_PRINTER_VALUE_OUT_RANGE);
        g_ipfmt.align = value;
        break;
    case PRINT_FORMAT_ITALIC:  // 是否斜体
        g_ipfmt.italic = value;
        m_iStatus = ERR_PRINTER_FORMAT_NOT_SUPPORT;
        break;
    case PRINT_FORMAT_HRILOC:  // HRI字符位置, 条码
        CHECK_STATUS_NO_RET(value < PF_HRILOC_NONE || value > PF_HRILOC_UPDOWN,
            ERR_PRINTER_VALUE_OUT_RANGE);
        g_ipfmt.hriloc = value;
        m_iStatus = ERR_PRINTER_FORMAT_NOT_SUPPORT;
        break;
    default:
        m_iStatus = ERR_PRINTER_FORMAT_NOT_SUPPORT;
        break;
    }
}

void RT80KM_Adaptor::GetDeviceSpec(DeviceSpec &spec)
{
    spec.setDensity = false;  // 不支持
    spec.width = 79.5;
    spec.canCutPaper = true;
    m_iStatus = SUCCESS;
}

int RT80KM_Adaptor::FeedPaper(int line)
{
    CHECK_STATUS(m_isOpen != true, ERR_DEVICE_NOT_OPEN);
    CHECK_STATUS(line < 1 || line >255, ERR_PRINTER_VALUE_OUT_RANGE);
    // 还要检查打印机状态， 是否电压过低、过热、缺纸等
    int paper_status = POS_Status_RTQueryTypeStatus(4);
    CHECK_STATUS(paper_status != 0, StatusConvert(paper_status));
    int ret = POS_Control_FeedLines(line);
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    return m_iStatus;
}

int RT80KM_Adaptor::CutPaper(int line,  int mode)
{
    CHECK_STATUS(line < 1 || line >255, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS((mode != PF_CUTMODE_ALL) && (mode != PF_CUTMODE_HALF), ERR_PRINTER_VALUE_OUT_RANGE);
    // 还要检查打印机状态， 是否电压过低、过热、缺纸等
    int paper_status = POS_Status_RTQueryTypeStatus(4);
    CHECK_STATUS(paper_status != 0, StatusConvert(paper_status));
    int ret = POS_Control_CutPaper(mode, line);
    CHECK_STATUS(ret != 0, StatusConvert(ret));
    return m_iStatus;
}

int RT80KM_Adaptor::AddText(int x, int y, const std::string& text)
{
    CHECK_STATUS(x < 0 || x > 72, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(y < 0 || y > 31, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(text.empty(), ERR_PRINTER_DATA_TOO_SHORT);

    return m_pTask->AddTask(PT_TYPE_TEXT, x, y, g_ipfmt, text);
}

int RT80KM_Adaptor::AddBitmap(int x, int y, const std::string& lpPath)
{
    CHECK_STATUS(x < 0 || x > 72, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(y < 0 || y > 31, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(lpPath.empty(), ERR_PRINTER_DATA_TOO_SHORT);
    return m_pTask->AddTask(PT_TYPE_BITMAP, x, y, g_ipfmt, lpPath);
}

int RT80KM_Adaptor::AddQRCode(int x, int y, int w, const std::string& qr)
{
    CHECK_STATUS(w < 1 || w > 6, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(x < 0 || x > 72, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(y < 0 || y > 31, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(qr.empty(), ERR_PRINTER_DATA_TOO_SHORT);
    CHECK_STATUS(qr.length() > 112, ERR_PRINTER_DATA_TOO_LONG);
    PrintFormat fmt = g_ipfmt;
    fmt.width = 3*w-2;
    return m_pTask->AddTask(PT_TYPE_QRCODE, x, y, fmt, qr);
}

int RT80KM_Adaptor::AddBarCode(int x, int y, BarCodeSpec &spec, const std::string& bar)
{
    CHECK_STATUS(x < 0 || x > 72, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(y < 0 || y > 31, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(spec.height <= 0 || spec.height > 255, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(spec.narrow < 1 || spec.narrow > 3, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(spec.wide < 1 || spec.wide > 6, ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS((spec.hri < PF_HRILOC_NONE) || (spec.hri > PF_HRILOC_UPDOWN), ERR_PRINTER_VALUE_OUT_RANGE);
    CHECK_STATUS(bar.empty(), ERR_PRINTER_DATA_TOO_SHORT);
    CHECK_STATUS(bar.length() > 26, ERR_PRINTER_DATA_TOO_LONG);
    CHECK_STATUS(bar.find_first_not_of("0123456789") != std::string::npos, ERR__PRINTER_DATA_PACKET_ERROR);

    PrintFormat fmt = g_ipfmt;
    int w = spec.narrow * spec.wide;
    fmt.width = (w*4+30)/17;  //  范围: [2, 6]
    fmt.height = spec.height;
    fmt.hriloc = spec.hri;
    return m_pTask->AddTask(PT_TYPE_BARCODE, x, y, fmt, bar);
}

void RT80KM_Adaptor::StartPrint(int timeout, PrintListener *listener)
{
    m_iStatus = m_pTask->StartPrint(timeout, listener);
}

// 插件接口实现
std::shared_ptr<IAdaptor> CreateAdaptor()
{
    return std::make_shared<RT80KM_Adaptor>();
}
Transport GetAccess(ACCESS_MODE mode, const char *dev)
{
    Transport tran;
    tran.mode = mode;
    strncpy(tran.dev, dev, sizeof(tran.dev));
    tran.timeout = 3000;
    if (mode == AM_SERIAL) {
        // SerialTransport serial;
        // serial.baudrate = 115200;
        // memcpy(tran.param, &serial, sizeof(serial));
        return tran;
    } else {
        // UsbTransport usb;
        // usb.bus_num = 0x0483;
        // usb.dev_num = 0x7540;
        // memcpy(tran.param, &usb, sizeof(usb));
        return tran;
    }
}

static Plugin g_plugin = {
    .CreateAdaptor = CreateAdaptor,
    .GetAccess = GetAccess,
    .version = "1.0",
    .name = "RT80KM",
    .desc = "RT80KM Printer Adaptor 1.0",
    .id = 0x0201   //
};

PLUGIN_INIT(&g_plugin)
